
[bits 16]
;void open_a20(void);
open_a20:
	in al, 0x92
	or al, 2
	out 0x92, al
	ret

;void clrScreen(void);
;int 10h version
clrScreen:
	mov	ax, 0600h
	mov	bx, 0700h
	mov	cx, 0		;(0, 0)
	mov	dx, 0184fh	;(80, 25)
	int	10h
	ret

;void dispStr(char* string, u16 len);
;in: ax = string, cx = len
;affect: bp, ax, bx, dx
dispStr:
	pusha
	mov bp, ax ;es:bp
	mov ax, 1301h
	mov bx, 0fh
	mov dx, 0
	int 10h
	popa
	ret

;====================================================================
[bits 32]
;read 512 bytes from lba
;void read_hard_disk(u32 lba, u32* buf)
;eax = lba, ds:ex = buf
;return: ebx = ebx + 512
;uses: eax, ecx, edx
read_hard_disk:
         push eax
         push ecx
         push edx

         push eax

         mov dx,0x1f2
         mov al,1
         out dx,al                       ;读取的扇区数

         inc dx                          ;0x1f3
         pop eax
         out dx,al                       ;LBA地址7~0

         inc dx                          ;0x1f4
         mov cl,8
         shr eax,cl
         out dx,al                       ;LBA地址15~8

         inc dx                          ;0x1f5
         shr eax,cl
         out dx,al                       ;LBA地址23~16

         inc dx                          ;0x1f6
         shr eax,cl
         or al,0xe0                      ;第一硬盘  LBA地址27~24
         out dx,al

         inc dx                          ;0x1f7
         mov al,0x20                     ;读命令
         out dx,al

  .waits:
         in al,dx
         and al,0x88
         cmp al,0x08
         jnz .waits                      ;不忙，且硬盘已准备好数据传输

         mov ecx,256                     ;总共要读取的字数
         mov dx,0x1f0
  .readw:
         in ax,dx
         mov [ebx],ax
         add ebx,2
         loop .readw

         pop edx
         pop ecx
         pop eax

         ret

;read kernel image to ds:ebx
;kernel image start sector: eax
read_kernel:
	call read_hard_disk
	mov eax, [edi] ;eax = kernel size
	ret

;make gdt descriptor
;input: eax = base; ebx = limit; ecx = type
;output: edx:eax, 64b descriptor
make_gdt_descriptor:
	;eax, low 32bit
	mov edx, eax
	shl eax, 16
	or ax, bx

	and edx, 0xffff0000
	rol edx, 8
	bswap edx

	;hight 4bit of limit
	xor bx, bx
	or edx, ebx

	or edx,ecx
ret

;fill one gdt item
;void fill_one_gdt(u32* addr, u32 type, u32 sel)
;addr: eax, addr[0] = offset base;  edi: base
;addr[1] = next_base; len = addr[1] - addr[0]
;type: ebx
;sel: ecx
;uses esi

fill_one_gdt:
	push esi
	push ecx ;save sel

	mov esi, eax ;esi = addr

	push ebx ;save type
	mov eax, [esi] ;base
	mov ebx, [esi + 4] ;total len
	sub ebx, eax
    dec ebx ;ebx = limit

	add eax, edi ;eax is obsolute address
	pop ecx ;ecx = type
    call make_gdt_descriptor

	pop ecx ;ecx = sel
	pop esi
    mov [esi + ecx], eax
    mov [esi + ecx + 4], edx

ret


;setup kernel GDT
;eax = 48bit GDTR ram address
setup_kernel_gdt:
	push edi
	push esi

	push eax
	;esi = gdt base address
	mov esi, [eax + 0x02]
	mov edi, kernel_base_addr

	;kernel sys code segment
	mov eax, kernel_base_addr + KERNEL_HEAD_SYS
	mov ebx, Descriptor(DA_LIMIT_1B, DA_C)
	mov ecx, sys_routine_seg_sel
	call fill_one_gdt

	;kernel data segment
	mov eax, kernel_base_addr + KERENL_HEAD_DATA
	mov ebx, Descriptor(DA_LIMIT_1B, DA_DRW)
	mov ecx, core_data_seg_sel
	call fill_one_gdt

	;kernel main code segment
	mov eax, kernel_base_addr + KERNEL_HEAD_CODE
	mov ebx, Descriptor(DA_LIMIT_1B, DA_C)
	mov ecx, core_code_seg_sel
	call fill_one_gdt

	;update gdt
	pop eax ;eax = gdtr
	mov word [eax], 63
	lgdt [eax]

	pop esi
	pop edi

ret



